package com.example.controller;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.example.exception.BaseException;
import com.example.model.api.Result;
import com.example.validator.ValidatorUtils;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@AllArgsConstructor
@RestController
@Tag(name = "aouth2登录")
@RequestMapping("admin")
public class AdminController {


    private Environment environment;
    // RegisteredClient Repository的作用
    //存储客户端信息：每个注册的OAuth 2.0客户端都有一个对应的RegisteredClient实例，其中包含该客户端的所有必要信息。
    //管理客户端生命周期：支持创建、读取、更新和删除（CRUD）操作，以维护客户端信息的最新状态。
    //提供查询功能：能够根据客户端ID或其他属性查找特定的RegisteredClient实例。
    //确保安全性：通过定义和验证客户端的权限和范围，帮助保护授权服务器免受未授权访问。
    private RegisteredClientRepository registeredClientRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @GetMapping("whoami")
    @Hidden // 此方法将被隐藏，不会出现在API文档中
    public Result<Map<String, Object>> whoAmI() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        JwtAuthenticationToken token = (JwtAuthenticationToken) authentication;
        Jwt principal = (Jwt) token.getPrincipal();
        Map<String, Object> claims = principal.getClaims();
        return new Result<Map<String, Object>>().ok(claims);
    }


    @Operation(summary = "用户名密码登录", description = "用户密码模式的登录接口")
    @PostMapping("login")
    public Result<Map<String, Object>> login(@RequestBody AdminLoginDTO adminLoginDTO) {
        //效验数据
        ValidatorUtils.validateEntity(adminLoginDTO);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String authorization = request.getHeader("Authorization");
        if (Strings.isNullOrEmpty(authorization)) {
            // Basic cGFzc3dvcmQtY2xpZW50OnBhc3N3b3JkLWNsaWVudC1zZWNyZXQ=
            throw new BaseException("Basic Auth请求头不能为空", HttpStatus.UNAUTHORIZED);
        }
        //解析 Authorization Basic Auth 请求头 Basic password-client:password-client-secret
        String clientInfo = new String(Base64Decoder.decode(authorization.replace("Basic ", "")));
        //判断是否是正确的client
        String clientId = clientInfo.split(":")[0], clientSecret = clientInfo.split(":")[1];

        RegisteredClient client = registeredClientRepository.findByClientId(clientId);
        if (Objects.isNull(client)) {
            throw new BaseException("客户端信息未在授权服务器注册", HttpStatus.UNAUTHORIZED);
        }
        if (!passwordEncoder.matches(clientSecret, client.getClientSecret())) {
            throw new BaseException("客户端凭证不匹配", HttpStatus.UNAUTHORIZED);
        } // zy1904807846818746369 44af39b11e6ff03e303a21ab2c946faf

        HashMap<String, Object> objectHashMap = new HashMap<>();
        objectHashMap.put("grant_type", AuthorizationGrantType.PASSWORD.getValue());
        objectHashMap.put("username", adminLoginDTO.getUsername());
        objectHashMap.put("password", adminLoginDTO.getPassword());
//        objectHashMap.put("scope", "openid"); // 默认scope为openid 没有 openid userinfo 会报错  "error": "insufficient_scope"
        objectHashMap.put("scope", "message.read");
        String body = HttpRequest.post(environment.getProperty("spring.security.oauth2.resourceserver.jwt.issuer-uri") + "/oauth2/token")
                .basicAuth(clientId, clientSecret)
                .form(objectHashMap)
                .execute().body();
        return new Result<Map<String, Object>>().ok(JSONUtil.toBean(body, Map.class));
    }

    @PostMapping("clientlogin")
    @Operation(summary = "客户端模式登录", description = "客户端模式登录")
    public Result<Map<String, Object>> clientlogin() {

        HashMap<String, Object> objectHashMap = new HashMap<>();
        objectHashMap.put("grant_type", AuthorizationGrantType.CLIENT_CREDENTIALS.getValue());
//        objectHashMap.put("scope", "openid"); // 默认scope为openid 没有 openid userinfo 会报错  "error": "insufficient_scope"
        objectHashMap.put("scope", "message.read");
        String body = HttpRequest.post(environment.getProperty("spring.security.oauth2.resourceserver.jwt.issuer-uri") + "/oauth2/token")
                .basicAuth("zy1904807846818746369", "44af39b11e6ff03e303a21ab2c946faf")
                .form(objectHashMap)
                .execute().body();
        return new Result<Map<String, Object>>().ok(JSONUtil.toBean(body, Map.class));
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Schema(description = "登录参数", required = true)
    public static class AdminLoginDTO {

        @Schema(description = "用户名", required = true, example = "admin")
        @NotBlank(message="{sysuser.username.require}")
        private String username;

        @Schema(description = "密码", required = true, example = "admin")
        @NotBlank(message="{sysuser.password.require}")
        private String password;
    }
}
